package net.lab0.wallstreet;

import java.io.IOException;
import java.util.List;

import net.lab0.wallstreet.ExampleGenerator.GeneratedData;

import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;

public class AccountingDilemmaTest
{
    private static final int tests = 10;
    
    @Test
    public void test1()
    {
        for (int i = 0; i < tests * tests; ++i)
        {
            ExampleGenerator generator = new ExampleGenerator(1, 10, 120);
            GeneratedData data = generator.generateData();
            List<Integer> result = AccountingDilemma.solve(data.transfer, data.paymentsList);
            
            standardValidate(data, result);
        }
    }
    
    @Test(timeout = 1000 * tests)
    public void test1k()
    {
        for (int i = 0; i < tests; ++i)
        {
            ExampleGenerator generator = new ExampleGenerator(1000, 10, 120);
            GeneratedData data = generator.generateData();
            List<Integer> result = AccountingDilemma.solve(data.transfer, data.paymentsList);
            
            standardValidate(data, result);
        }
    }
    
    @Test(timeout = 1000 * tests)
    public void test1M()
    {
        for (int i = 0; i < tests; ++i)
        {
            ExampleGenerator generator = new ExampleGenerator(1000 * 1000, 10, 120);
            GeneratedData data = generator.generateData();
            List<Integer> result = AccountingDilemma.solve(data.transfer, data.paymentsList);
            
            standardValidate(data, result);
        }
    }
    
    @Ignore
    @Test(timeout = 1000 * tests)
    public void test10M()
    {
        for (int i = 0; i < tests; ++i)
        {
            ExampleGenerator generator = new ExampleGenerator(10 * 1000 * 1000, 10, 120);
            GeneratedData data = generator.generateData();
            List<Integer> result = AccountingDilemma.solve(data.transfer, data.paymentsList);
            
            standardValidate(data, result);
        }
    }
    
    private void standardValidate(GeneratedData data, List<Integer> result)
    {
        if (result == null)
        {
            if (data.possible)
            {
                Assert.fail();
            }
        }
        else
        {
            int total = 0;
            for (int r : result)
            {
                total += r;
            }
            Assert.assertEquals(data.transfer, total);
        }
    }
    
    private void validate(DataSource source, boolean possible)
    throws IOException
    {
        source.readData();
        List<Integer> result = AccountingDilemma.solve(source.getBankTransfer(), source.getDuePayments());
        
        if (result == null)
        {
            if (possible)
            {
                Assert.fail();
            }
        }
        else
        {
            if (!possible)
            {
                Assert.fail();
            }
            
            int total = 0;
            for (int r : result)
            {
                total += r;
            }
            Assert.assertEquals(source.getBankTransfer(), total);
        }
    }
    
    @Test
    public void testExample()
    throws IOException
    {
        DataSource source = new DataSource("./inputs/example.txt");
        validate(source, true);
    }
    
    @Test(timeout = 5000)
    public void worstCase1()
    throws IOException
    {
        DataSource source = new DataSource("./inputs/manual_worst_case_1.txt");
        validate(source, false);
    }
    
    @Test(timeout = 5000)
    public void worstCase2()
    throws IOException
    {
        DataSource source = new DataSource("./inputs/manual_worst_case_2.txt");
        validate(source, false);
    }
    
     @Test(timeout = 1000)
    public void testDecreasing()
    {
        GeneratedData data = ExampleGenerator.generateDecreasing();
        List<Integer> result = AccountingDilemma.solve(data.transfer, data.paymentsList);
        
        standardValidate(data, result);
    }
    
    @Test
    public void testPrimes()
    {
        GeneratedData data = ExampleGenerator.generatePrimes();
        List<Integer> result = AccountingDilemma.solve(data.transfer, data.paymentsList);
        
        standardValidate(data, result);
    }
}
